/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package taskmanager;

import java.io.File;
import java.io.FileWriter;
import java.io.IOException;
import java.io.StringWriter;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.transform.OutputKeys;
import javax.xml.transform.Transformer;
import javax.xml.transform.TransformerFactory;
import javax.xml.transform.dom.DOMSource;
import javax.xml.transform.stream.StreamResult;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
import org.w3c.dom.Text;

/**
 *
 * @author Pavel
 * 
 *
 */
public class XMLStorage implements Storage {

    private static final String filename = "tasks.xml";

    /**
     * Loads all tasks from XML storage
     * 
     * @return List of all the tasks in the storage
     * 
     *
     */
    private Document doc;
    
    public XMLStorage()
    {
        File file = new File(filename);
        if (!file.exists())
        {
            try 
            {
                file.createNewFile();
            } catch (IOException ex) 
            {
                
            }
        }
    }
    
    public List<Task> loadAll() {
        ArrayList<Task> result = new ArrayList<Task>();
        try {
            File fXmlFile = new File(filename);
            DocumentBuilderFactory dbFactory = DocumentBuilderFactory.newInstance();
            DocumentBuilder dBuilder = dbFactory.newDocumentBuilder();
            doc = dBuilder.parse(fXmlFile);
            doc.getDocumentElement().normalize();

            NodeList nList = doc.getElementsByTagName("Task");

            if (nList != null) {
                for (int i = 0; i < nList.getLength(); i++) {
                    result.add(ElementToTask((Element) nList.item(i)));
                }
            }
            return result;
        } catch (Exception e) {
            System.out.println(e.toString());
            return result;
        }
    }

    /**
     * Saves all the tasks into the XML storage
     * 
     * @param taskList   List of tasks
     * 
     *
     */
    public void saveAll(List taskList) {
        try {
            /////////////////////////////
            //Creating an empty XML Document

            //We need a Document
            DocumentBuilderFactory dbfac = DocumentBuilderFactory.newInstance();
            DocumentBuilder docBuilder = dbfac.newDocumentBuilder();
            doc = docBuilder.newDocument();

            ////////////////////////
            //Creating the XML tree

            //create the root element and add it to the document
            Element root = doc.createElement("TaskList");
            doc.appendChild(root);

            for (Object currentTask : taskList) {
                Element child = TaskToElement((Task) currentTask, doc);
                root.appendChild(child);
            }


            /////////////////
            //Output the XML

            //set up a transformer
            TransformerFactory transfac = TransformerFactory.newInstance();
            Transformer trans = transfac.newTransformer();
            trans.setOutputProperty(OutputKeys.OMIT_XML_DECLARATION, "yes");
            trans.setOutputProperty(OutputKeys.INDENT, "yes");

            //create string from xml tree
            StringWriter sw = new StringWriter();
            StreamResult result = new StreamResult(sw);
            DOMSource source = new DOMSource(doc);
            trans.transform(source, result);
            String xmlString = sw.toString();
            FileWriter fw = new FileWriter(filename);
            fw.write(xmlString);
            fw.close();

        } catch (Exception e) {
            System.out.println(e.toString());
        }

    }  
    
    /**
     * Turn a task to XML format
     * 
     * @param task    The task going to be formatted to XML  
     * @param doc     The document for a formatted task
     * 
     * 
     * @return taskElement   Task formatted to XML
     * 
     *
     */
    private Element TaskToElement(Task task, Document doc) {
        Element taskElement = doc.createElement("Task");
        AddProperty(doc, taskElement, "Description", task.getDescription());
        AddProperty(doc, taskElement, "Name", task.getName());
        AddProperty(doc, taskElement, "Contacts", task.getContacts());
        AddProperty(doc, taskElement, "Closed", String.valueOf(task.isClosed()));
        /*
        AddProperty(doc, taskElement, "ID", String.valueOf(task.getId()));        
        AddProperty(doc, taskElement, "Delayed", String.valueOf(task.isDelayed()));
        AddProperty(doc, taskElement, "Overdue", String.valueOf(task.isOverdue()));
        AddProperty(doc, taskElement, "Priority", String.valueOf(task.getPriority()));
         * 
         */
        SimpleDateFormat sdf = new SimpleDateFormat();
        String date = sdf.format(task.getDueDate());
        AddProperty(doc, taskElement, "DueDate", date);

        return taskElement;
    }

    /**
     * Adds child elements to a given element
     * 
     *   
     * @param doc     The XML document with tasks
     * @param element    The current element in the document
     * @param name      Name of the element
     * @param value     Value of the element
     * 
     *
     */
    
    private void AddProperty(Document doc, Element element, String name, String value) {
        Element subElement = doc.createElement(name);
        Text text = doc.createTextNode(value);
        Node appendChild = subElement.appendChild(text);
        element.appendChild(subElement);
    }
    
    /**
     * Converts an element into a task
     *      
     * @param element    The current element     
     * 
     *
     */

    private Task ElementToTask(Element element) {
        Task result = new Task();

        result.setName(getTagValue("Name", element));
        result.setDescription(getTagValue("Description", element));
        result.setClosed(Boolean.valueOf(getTagValue("Closed", element)));
        result.setContacts(getTagValue("Contacts", element));
        /*
        result.setDelayed(Boolean.valueOf(getTagValue("Delayed", element)));               
        result.setOverdue(Boolean.valueOf(getTagValue("Overdue", element)));        
        result.setPriority(Integer.valueOf(getTagValue("Priority", element)));        
        result.setId(Integer.valueOf(getTagValue("ID", element)));
         */
        SimpleDateFormat sdf = new SimpleDateFormat();
        try {
            result.setDueDate(sdf.parse(getTagValue("DueDate", element)));
        } catch (ParseException ex) {
            Logger.getLogger(XMLStorage.class.getName()).log(Level.SEVERE, null, ex);
        }

        return result;
    }

    
    /**
     * Adds child elements to a given element
     * 
     *   
     * @param sTag      Name of child element   
     * @param element    The current element  
     * 
     * @return     Text content of the child element
     */
    private static String getTagValue(String sTag, Element element) {
        return element.getElementsByTagName(sTag).item(0).getTextContent();
    }
}
